package product

import (
	"context"
	// "fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/utils/pointy"
	"mall/service/backend/api/internal/logic/product/util"
	"mall/service/backend/api/internal/logic/utils"
	"mall/service/backend/api/internal/logic/utils/parse"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/common/i18n"
	"mall/service/product/rpc/productclient"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetProductListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductListLogic {
	return &GetProductListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetProductListLogic) GetProductList(req *types.ProductListReq) (*types.ProductListResp, error) {
	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	orderBys := util.ParseSorterNew(req.Sorter)
	filterBys := util.ParseFilterNew(req.Filter, req.Type)

	var ids string
	var search *string
	if req.Search != nil && len(strings.TrimSpace(*req.Search)) > 0 { // 前端可以搜名称或者ID
		reqSearch := strings.TrimSpace(*req.Search)
		if _, err := strconv.ParseInt(reqSearch, 10, 64); err == nil {
			ids = reqSearch
		} else {
			search = pointy.GetPointer(reqSearch)
		}
	}

	if req.Id != nil && *req.Id > 0 {
		ids = strconv.FormatInt(int64(*req.Id), 10)
	}
	if req.ProductIds != nil && len(strings.TrimSpace(*req.ProductIds)) > 0 {
		ids = strings.TrimSpace(*req.ProductIds)
	}
	var bids []string
	if req.BrandId != nil && *req.BrandId > 0 {
		bids = append(bids, strconv.FormatUint(*req.BrandId, 10))
	}
	var pids []string
	if req.PerfumeId != nil && *req.PerfumeId > 0 {
		pids = append(pids, strconv.FormatUint(*req.PerfumeId, 10))
	}
	var tids []string
	if req.TagId != nil && *req.TagId > 0 {
		tids = append(tids, strconv.FormatUint(*req.TagId, 10))
	}

	data, err := l.svcCtx.ProductRpc.BackendGetProductList(l.ctx, &productclient.ProductListReq{
		Page:        page,
		PageSize:    pageSize,
		Ids:         pointy.GetPointer(ids),
		Title:       req.Title,
		Slug:        req.Slug,
		Excerpt:     req.Excerpt,
		Search:      search,
		CategoryId:  req.CategoryId,
		ParentId:    req.ParentId,
		BrandIds:    pointy.GetPointer(strings.Join(bids, ",")),
		PerfumeIds:  pointy.GetPointer(strings.Join(pids, ",")),
		CategoryIds: pointy.GetPointer(strings.Join(tids, ",")),
		Status:      req.Status,
		StartTime:   req.StartTime,
		EndTime:     req.EndTime,
		OrderBy:     orderBys,
		FilterBy:    filterBys,
		WithMeta:    req.WithMeta,
		WithMedia:   req.WithMedia,
		WithTag:     req.WithTag,
		WithEntry:   req.WithEntry,
		WithContent: req.WithContent,
		WithAttr:    req.WithAttr,
		WithSpec:    req.WithSpec,
		WithSku:     req.WithSku,
		WithTracing: req.WithTracing,
		Diagnose:    req.Diagnose,
	})
	if err != nil {
		return nil, err
	}

	resp := &types.ProductListResp{
		BaseDataInfo: types.BaseDataInfo{
			Success: true,
			Msg:     l.svcCtx.Trans.Trans(l.ctx, i18n.Success),
		},
		Data: types.ProductListInfo{
			BaseListInfo: types.BaseListInfo{
				Current:  page,
				PageSize: pageSize,
				Total:    data.GetTotal(),
			},
			StatusStatisticMap: data.StatusStatisticMap,
		},
	}

	for _, v := range data.List {
		var meta []*types.MetaInfo
		var media []*types.MediaInfo
		var categories []*types.ProductTermInfo
		var tags []*types.ProductTermInfo

		var photoCount *uint32
		var viewCount *uint32
		var forwardCount *uint32
		var pendingStatus *uint32

		var gemPriceMin *string
		var gemPriceMax *string
		var retailPriceMin *string
		var retailPriceMax *string
		var saleCount *uint32
		var isNew *uint32
		var isHot *uint32
		var sync *uint32
		var syncAt *string
		var stock *uint32
		var relationPerfumeId *uint64
		var relationPerfumeName *string
		var relationPerfumeSlug *string
		var relationBrandId *uint64
		var relationBrandName *string
		var relationBrandSlug *string
		var abbr *string

		if len(v.Meta) > 0 {
			for _, m := range v.Meta {
				if m.Key != nil && m.Value != nil {
					switch *m.Key {
					case "photoCount":
						if i, err := strconv.ParseInt(*m.Value, 10, 32); err == nil {
							photoCount = pointy.GetPointer(uint32(i))
						}
					case "viewCount":
						if i, err := strconv.ParseInt(*m.Value, 10, 32); err == nil {
							viewCount = pointy.GetPointer(uint32(i))
						}
					case "forwardCount":
						if i, err := strconv.ParseInt(*m.Value, 10, 32); err == nil {
							forwardCount = pointy.GetPointer(uint32(i))
						}
					case "pendingStatus":
						if i, err := strconv.ParseInt(*m.Value, 10, 32); err == nil {
							pendingStatus = pointy.GetPointer(uint32(i))
						}
					case "gemPriceMin":
						gemPriceMin = m.Value
					case "gemPriceMax":
						gemPriceMax = m.Value
					case "retailPriceMin":
						retailPriceMin = m.Value
					case "retailPriceMax":
						retailPriceMax = m.Value
					case "saleCount":
						if i, err := strconv.ParseInt(*m.Value, 10, 32); err == nil {
							saleCount = pointy.GetPointer(uint32(i))
						}
					case "isNew":
						if *m.Value == "1" {
							isNew = pointy.GetPointer(uint32(1))
						}
					case "isHot":
						if *m.Value == "1" {
							isHot = pointy.GetPointer(uint32(1))
						}
					case "sync":
						if *m.Value == "1" {
							sync = pointy.GetPointer(uint32(1))
						}
					case "syncFrom":
						syncAt = m.Value
					case "stock":
						if i, err := strconv.ParseInt(*m.Value, 10, 32); err == nil {
							stock = pointy.GetPointer(uint32(i))
						}
					case "abbr":
						abbr = m.Value
					default:
						meta = append(meta, &types.MetaInfo{
							Id:    m.Id,
							Key:   m.Key,
							Value: m.Value,
						})
					}
				}
			}
		}

		if len(v.Relations) > 0 {
			for _, m := range v.Relations {
				if m.Id != nil && *m.Id > 0 && m.Key != nil {
					switch *m.Key {
					case globalkey.ProductRelationNamePerfume:
						relationPerfumeId = m.Id
						relationPerfumeName = m.Name
						relationPerfumeSlug = m.Slug
					case globalkey.ProductRelationNameBrand:
						relationBrandId = m.Id
						relationBrandName = m.Name
						relationBrandSlug = m.Slug
					}
				}
			}
		}

		if len(v.Media) > 0 {
			for _, m := range v.Media {
				var url string
				if m.Url != nil && len(*m.Url) > 0 {
					url = *m.Url
				}
				if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
					url = *m.Uri
				}
				filename, mimeType, metaData := utils.ParseMetaData(m.MetaData)
				media = append(media, &types.MediaInfo{
					Uid:       m.Uid,
					Id:        m.Id,
					Thumbnail: m.Thumbnail,
					Order:     m.Order,
					Url:       pointy.GetPointer(url),
					Name:      pointy.GetPointer(filename),
					MimeType:  pointy.GetPointer(mimeType),
					AltText:   m.AltText,
					MetaData:  pointy.GetPointer(metaData),
				})
			}
		}

		if len(v.Categories) > 0 {
			for _, m := range v.Categories {
				categories = append(categories, &types.ProductTermInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id: m.Id,
					},
					Name: m.Name,
					Slug: m.Slug,
				})
			}
		}

		if len(v.Tags) > 0 {
			for _, m := range v.Tags {
				tags = append(tags, &types.ProductTermInfo{
					BaseIDInfo: types.BaseIDInfo{
						Id: m.Id,
					},
					Name: m.Name,
					Slug: m.Slug,
				})
			}
		}

		nowString := modelx.FormatTime(time.Now(), "")
		var attrs []*types.ProductAttrInfo
		if len(v.Attrs) > 0 {
			for _, attr := range v.Attrs {
				if len(attr.Options) > 0 {
					var options []*types.ProductAttrOptInfo
					for _, opt := range attr.Options {
						var key *string
						if opt.Uid != nil {
							key = pointy.GetPointer("opt_" + strconv.FormatInt(int64(*opt.Uid), 10) + "_" + nowString)
						} else {
							key = pointy.GetPointer("opt_0_" + nowString)
						}
						options = append(options, &types.ProductAttrOptInfo{
							Uid:    opt.Uid,
							Id:     opt.Id,
							Key:    key,
							Name:   opt.Name,
							Slug:   opt.Slug,
							ImgId:  opt.MediaId,
							ImgUrl: opt.MediaUrl,
						})
					}
					var key *string
					if attr.Uid != nil {
						key = pointy.GetPointer("attr_" + strconv.FormatInt(int64(*attr.Uid), 10) + "_" + nowString)
					} else {
						key = pointy.GetPointer("attr_0_" + nowString)
					}
					attrs = append(attrs, &types.ProductAttrInfo{
						Uid:      attr.Uid,
						Id:       attr.Id,
						Key:      key,
						Name:     attr.Name,
						Slug:     attr.Slug,
						HasImage: attr.HasMedia,
						Options:  options,
					})
				}
			}
		}

		var specs []*types.ProductAttrInfo
		if len(v.Specs) > 0 {
			for _, spec := range v.Specs {
				if len(spec.Options) > 0 {
					var options []*types.ProductAttrOptInfo
					for _, opt := range spec.Options {
						var key *string
						if opt.Uid != nil {
							key = pointy.GetPointer("opt_" + strconv.FormatInt(int64(*opt.Uid), 10) + "_" + nowString)
						} else {
							key = pointy.GetPointer("opt_0_" + nowString)
						}
						options = append(options, &types.ProductAttrOptInfo{
							Uid:    opt.Uid,
							Id:     opt.Id,
							Key:    key,
							Name:   opt.Name,
							Slug:   opt.Slug,
							ImgId:  opt.MediaId,
							ImgUrl: opt.MediaUrl,
						})
					}
					var key *string
					if spec.Uid != nil {
						key = pointy.GetPointer("spec_" + strconv.FormatInt(int64(*spec.Uid), 10) + "_" + nowString)
					} else {
						key = pointy.GetPointer("spec_0_" + nowString)
					}
					specs = append(specs, &types.ProductAttrInfo{
						Uid:      spec.Uid,
						Id:       spec.Id,
						Key:      key,
						Name:     spec.Name,
						Slug:     spec.Slug,
						HasImage: spec.HasMedia,
						Options:  options,
					})
				}
			}
		}

		var skus []*types.ProductVariationInfo
		if len(v.Skus) > 0 {
			for _, sku := range v.Skus {
				var optKeys []string
				if len(sku.Specs) > 0 {
					for _, spec := range sku.Specs {
						if len(spec.Options) > 0 {
							for _, opt := range spec.Options {
								if opt.Label != nil {
									optKeys = append(optKeys, *opt.Label)
								}
							}
						}
					}
				}
				skus = append(skus, &types.ProductVariationInfo{
					Id:           sku.Id,
					Key:          pointy.GetPointer(strings.Join(optKeys, "_-_")),
					RetailPrice:  sku.RetailPrice,
					CounterPrice: sku.CounterPrice,
					GemPrice:     sku.GemPrice,
					Inventory:    sku.Inventory,
					Weight:       sku.Weight,
					SkuCode:      sku.SkuCode,
					Status:       sku.Status,
					SaleCount:    sku.SaleCount,
					ImgId:        sku.MediaId,
					ImgUrl:       sku.MediaUrl,
				})
			}
		}

		option := util.GetAuditOptionByStatus(v.Status)
		var uri *string
		if v.Uri != nil && len(*v.Uri) > 0 {
			uri = pointy.GetPointer(l.svcCtx.Config.NfsConf.SiteUrl + *v.Uri)
		}

		resp.Data.List = append(resp.Data.List, &types.ProductInfo{
			BaseIDInfo: types.BaseIDInfo{
				Id:         v.Id,
				CreatedAt:  v.CreatedAt,
				UpdatedAt:  v.UpdatedAt,
				DeletedAt:  v.DeletedAt,
				CanAccept:  option.CanAccept,
				CanReject:  option.CanReject,
				CanRemove:  option.CanRemove,
				CanRestore: option.CanRestore,
			},
			Title:          v.Title,
			Slug:           v.Slug,
			Content:        v.ContentFiltered,
			ContentHtml:    v.Content,
			Excerpt:        v.Excerpt,
			CategoryId:     v.CategoryId,
			ParentId:       v.ParentId,
			AuthorId:       v.AuthorId,
			Status:         v.Status,
			PendingStatus:  pendingStatus,
			CommentStatus:  v.CommentStatus,
			Sort:           v.Sort,
			Tracing:        v.TracingFiltered,
			TracingHtml:    v.Tracing,
			Uri:            uri,
			VirtualType:    v.VirtualType,
			Sticky:         v.Sticky,
			PhotoCount:     photoCount,
			ViewCount:      viewCount,
			ForwardCount:   forwardCount,
			CommentCount:   v.CommentCount,
			GemPriceMin:    gemPriceMin,
			GemPriceMax:    gemPriceMax,
			RetailPriceMin: retailPriceMin,
			RetailPriceMax: retailPriceMax,
			SaleCount:      saleCount,
			IsNew:          isNew,
			IsHot:          isHot,
			Sync:           sync,
			SyncAt:         syncAt,
			Stock:          stock,
			Abbr:           abbr,
			PerfumeId:      relationPerfumeId,
			PerfumeName:    relationPerfumeName,
			PerfumeSlug:    relationPerfumeSlug,
			BrandId:        relationBrandId,
			BrandName:      relationBrandName,
			BrandSlug:      relationBrandSlug,
			CanSubmit:      option.CanSubmit,
			CanSync:        option.CanSync,
			CanShelf:       option.CanShelf,
			CanOffShelf:    option.CanOffShelf,
			PreviewLink:    pointy.GetPointer(l.svcCtx.Config.Query.PreviewLink + "&productId=" + strconv.FormatInt(int64(*v.Id), 10)),

			Meta:       meta,
			Media:      media,
			Categories: categories,
			Tags:       tags,
			Attrs:      attrs,
			Specs:      specs,
			Skus:       skus,
		})
	}

	return resp, nil
}
